Skip to content

BIP445: FROST Signing Protocol for BIP340 Signatures#2070

Open
siv2r wants to merge 14 commits into
bitcoin:masterfrom
siv2r:bip-frost-signing
Open

BIP445: FROST Signing Protocol for BIP340 Signatures#2070
siv2r wants to merge 14 commits into
bitcoin:masterfrom
siv2r:bip-frost-signing

Conversation

@siv2r

@siv2r siv2r commented Jan 3, 2026

Copy link
Copy Markdown
Contributor

This PR adds a BIP for the FROST (Flexible Round-Optimized Schnorr Threshold) signing protocol. The development repository is at https://github.com/siv2r/bip-frost-signing.

There already exists RFC 9591, which standardizes the two-round FROST signing protocol, but it is incompatible with Bitcoin's BIP340 X-only public keys. This BIP bridges that gap by providing a BIP340-compatible variant of FROST.

This BIP standardizes the FROST3 variant (Section 2.3 of the ROAST paper). This variant shares significant similarities with the MuSig2 signing protocol (BIP327). Accordingly, this BIP follows the core design principles of BIP327, and many sections have been directly adapted from it.

FROST key generation is out of scope for this BIP. There are sister BIPs such as ChillDKG and Trusted Dealer Generation that specify key generation mechanisms. This BIP must be used in conjunction with either of those for the full workflow from key generation to signature creation. Careful consideration has been taken to ensure the terminology in this BIP matches that of ChillDKG.

There are multiple (experimental) implementations of this specification:

  • The reference Python implementation included in this PR
  • secp256k1-zkp FROST module (yet to implement the test vectors)
  • FROST-BIP340 TODO: verify if this impl is compatible with our test vectors
  • secp256kfun (implements ChillDKG with FROST signing) TODO: verify if this impl is compatible with our test vectors

Disclosure: AI has been used to rephrase paragraphs for clarity, refactor certain sections of the reference code, and review pull requests made to the development repository.

Feedback is appreciated! Please comment on this pull request or open an issue at https://github.com/siv2r/bip-frost-signing for any feedback. Thank you!

cc @jonasnick @real-or-random @jesseposner

@siv2r

siv2r commented Jan 3, 2026

Copy link
Copy Markdown
Contributor Author

I'll fix the typos check soon

@siv2r

siv2r commented Jan 3, 2026

Copy link
Copy Markdown
Contributor Author

I can see that GitHub's file changes view shows only one file at a time due to the large number of changes. This is because the reference implementation includes dependencies and auxiliary materials:

  • The reference code uses secp256k1lab python library (vendored as a git subtree, ~20 files) for scalar and group arithmetic. I can remove this from the PR when the library is integrated into this repository (RFC: Integrate secp256k1lab v1.0.0 as subtree, use it for BIP-374 #1855).
  • Auxiliary files include docs/partialsig_forgery.md (which I can move to a gist if preferred) and a test vector generation script (~1400 lines). I can exclude these if necessary.

@murchandamus murchandamus changed the title Add BIP: FROST Signing for BIP340-compatible Threshold Signatures BIP Draft: FROST Signing Protocol for BIP340 Schnorr Signatures Jan 6, 2026

@murchandamus murchandamus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a first glance, but I noticed a few issues:

Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
@murchandamus murchandamus changed the title BIP Draft: FROST Signing Protocol for BIP340 Schnorr Signatures BIP Draft: FROST Signing Protocol for BIP340 Signatures Jan 8, 2026

@murchandamus murchandamus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick turn-around. It’s on my todo list to give this a more thorough look, but it might take a bit. If you can motivate some other reviewers meanwhile, that would also be welcome.

Comment thread bip-frost-signing.md Outdated
@siv2r

siv2r commented Jan 9, 2026

Copy link
Copy Markdown
Contributor Author

If you can motivate some other reviewers meanwhile, that would also be welcome.

I've shared it with most of the Bitcoin cryptographers I know and will post it on Twitter and the Bitcoin dev groups I'm part of. Hopefully that will bring in more reviewers!

@DarkWindman DarkWindman left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! Quite a remarkable job! We found a few minor issues, and correcting them would improve the overall specification of the BIP.

Comment thread bip-0445.md
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-0445.md
Comment thread bip-frost-signing.md Outdated
Comment thread bip-0445.md
Comment thread bip-0445.md
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated

@Christewart Christewart left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned on X i'm working on this, so you will likely see more comments in the future. Another nice-to-have would be a table of contents (example) as most other BIPs have this. Perhaps this is a limitation of the .md document vs .mediawiki. Not sure.

Comment thread bip-0445.md Outdated
Comment thread bip-0445.md
@siv2r

siv2r commented Jan 21, 2026

Copy link
Copy Markdown
Contributor Author

Another nice-to-have would be a table of contents (example) as most other BIPs have this. Perhaps this is a limitation of the .md document vs .mediawiki. Not sure.

Yes, it's a .md issue, this bip initially had a manually written table of contents but was removed after #2070 (comment)

@murchandamus

Copy link
Copy Markdown
Member

As I mentioned on X i'm working on this, so you will likely see more comments in the future. Another nice-to-have would be a table of contents (example) as most other BIPs have this. Perhaps this is a limitation of the .md document vs .mediawiki. Not sure.

Click there. ;)

image

@Christewart

Copy link
Copy Markdown
Contributor

As I mentioned on X i'm working on this, so you will likely see more comments in the future. Another nice-to-have would be a table of contents (example) as most other BIPs have this. Perhaps this is a limitation of the .md document vs .mediawiki. Not sure.

Click there. ;)

Thank you! TIL :-)

@DarkWindman DarkWindman left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few additional minor issues and questions.

Comment thread bip-0445.md
Comment thread bip-frost-signing.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md
Comment thread bip-0445.md
@siv2r

siv2r commented Jan 25, 2026

Copy link
Copy Markdown
Contributor Author

@DarkWindman thanks a lot for the review! I've addressed most of your review comments in a88f033.

@murchandamus murchandamus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From an editorial standpoint, it looks pretty good and like all the required sections are present. I have read the proposal only partially, and do not have the expertise to fully understand all aspects, so I cannot comment on the technical soundness and whether the Specification is complete and sufficient.

Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
@murchandamus murchandamus added the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label Jan 27, 2026
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-0445/python/vectors/sign_verify_vectors.json Outdated
@murchandamus

murchandamus commented Jan 30, 2026

Copy link
Copy Markdown
Member

Let’s call this BIP 445. Please add an entry for your proposal in the README table, in the preamble update the BIP header to 445 and Assigned header to 2026-01-30, and update your documents file name as well as the auxiliary file directory.

@murchandamus murchandamus changed the title BIP Draft: FROST Signing Protocol for BIP340 Signatures BIP445: FROST Signing Protocol for BIP340 Signatures Jan 30, 2026
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-frost-signing.md Outdated
Comment thread bip-0445/python/vectors/det_sign_vectors.json Outdated
@jonasnick

Copy link
Copy Markdown
Contributor

I think the BIP should cite https://eprint.iacr.org/2024/436.pdf because it proves that Taproot and BIP 32 tweaking are secure.

Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
Comment thread bip-0445.md

@theStack theStack left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went over the reference implementation and verified that it matches the specification, modulo one blaming deviation, see below. The rest of the comments are mostly stylistic nits, feel free to ignore.

Comment thread bip-0445/python/frost_ref/signing.py Outdated
Comment thread bip-0445/python/frost_ref/signing.py Outdated
Comment thread bip-0445/python/frost_ref/signing.py Outdated
Comment thread bip-0445/python/frost_ref/signing.py Outdated
Comment thread bip-0445/python/frost_ref/signing.py Outdated
Comment thread bip-0445/python/frost_ref/signing.py Outdated
Comment thread bip-0445/python/frost_ref/signing.py Outdated
Comment thread bip-0445.md Outdated
@siv2r

siv2r commented May 25, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the review comments and added the test vector coverage suggested in #2070 (comment). The only thing still open there is vectors for multiple threshold (t, n) configs, which is next on my list.

I also went over the spec and reference code again and fixed a few more mismatches.

Comment thread bip-0445/python/frost_ref/signing.py Outdated
Comment thread bip-0445/python/frost_ref/signing.py
@siv2r

siv2r commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

I've added multiple (t, n) configs to the test vectors. They now run across 4 configs, (2,3), (1,3), (3,3), and (3,5), instead of the single (2,3) setup we had before. That takes the total from 68 to 250 cases. Here's the per-API breakdown:

API Before Now
nonce_gen 5 5
nonce_agg 5 5
sign_verify 25 93
tweak 9 44
det_sign 19 81
sig_agg 5 22
Total 68 250

nonce_gen and nonce_agg don't depend on (t, n), so they stay the same. The rest grew because they now cover all 4 configs.

I also re-read the BIP text and the reference spec and fixed a few inconsistencies.

As far as I can tell, this addresses all the open review comments. I think the BIP is good to merge once the other reviewers are happy with it.

@murchandamus

Copy link
Copy Markdown
Member

@siv2r: Okay cool, I resubscribed to the PR and have added it to my review queue.

@mllwchrry mllwchrry left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the BIP once again. Everything looks great! Found only two inconsistencies.

Comment thread bip-0445.md Outdated
Comment thread bip-0445.md Outdated
@siv2r

siv2r commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

The changelog is at 0.6.0, using the same semver-style scheme as BIP327.

BIP327 bumped to 1.0.0 when its number was assigned. I didn't follow that for 445 because it was still under active review with suggestions coming in, so tagging it 1.0.0 felt premature back then. It's now had a good stretch of review without any drastic changes suggested.

@murchandamus should this be bumped to 1.0.0 just before merge? And what's the usual convention for bips changelog versioning?

@murchandamus

murchandamus commented Jun 26, 2026

Copy link
Copy Markdown
Member

@siv2r: Version 1.0.0 is usually reserved for the stage of the BIP that is advanced to Complete. You can find more guidance on Changelog Section and Version Header in BIP3.

@murchandamus murchandamus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gave this another fast read. From an editorial perspective, this looks properly formatted and complete (when considering the footnotes and "Remarks on Security and Correctness" the stand-in for the Rationale section). I did not spend the time to fully understand the scheme and only skimmed the algorithm sections. I saw that there was a reference implementation included and that it had some tests. Given the many review comments, and extensive Changelog, it seems to have been read much more carefully by multiple other more qualified reviewers.

From an editorial perspective, I’d be happy to publish this whenever the author and reviewers indicate that the proposal is clear, comprehensive, and mature enough to do so.

Comment thread bip-0445.md Outdated
@murchandamus murchandamus removed the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label Jun 26, 2026
@murchandamus

Copy link
Copy Markdown
Member

@siv2r: It sounds like you think it’s ready for publication, some reviewers have indicated the same. Let’s merge this in a week (on or after July 6th) unless more things crop up. Or if you want it published before then, please let me know.

@siv2r

siv2r commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

Let’s merge this in a week (on or after July 6th) unless more things crop up

Sounds good! I'll do one final review this week, and will update here if anything comes up. Else we can merge on July 6th.

@DarkWindman DarkWindman left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit; everything else looks good to me!

Comment thread bip-0445.md
Moreover, this method is not compatible with the defense-in-depth mechanism described in the previous paragraph.
Generating the nonces ahead of time in this manner does not affect the unforgeability of the scheme.

[^det-nonce]: A signer's partial signature has the form *s = k<sub>1</sub> + b k<sub>2</sub> + c &lambda; d*, where *(k<sub>1</sub>, k<sub>2</sub>)* is the secret nonce, *d* is the secret share, and the coefficients *b* (nonce binding), *c* (challenge), and *&lambda;* (Lagrange interpolation over the signer set) are public. With deterministic nonces, an honest signer reproduces the identical *(k<sub>1</sub>, k<sub>2</sub>)* on every signing attempt for a given message. A malicious co-signer exploits this by replaying the session three times on that message and contributing a different nonce each time, which changes the aggregate nonce and therefore both *b* and *c*, while *&lambda;* stays fixed because the signer set is unchanged. The three resulting partial signatures form three linear equations in the unknowns *(k<sub>1</sub>, k<sub>2</sub>, d)*, which the co-signer solves to recover the victim's secret share *d*. This adapts the derandomization attack from Section 3.2 ("Derandomized Signing") of [[MPSW18][musig]], and a similar replay attack is noted for the stateless deterministic signing case in [^det-signer-set].

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since e is used to denote the challenge later on, it would be better to use e instead of c here as well, for consistency.

@real-or-random

Copy link
Copy Markdown
Contributor

Sorry for being late with a comment of this kind, but I think this should somehow take into account the "plausible attack on adaptive security of threshold Schnorr signatures" by Elizabeth Crites and Alistair Stewart (paper, talk).

tl;dr of the paper:

  • The result of the attack (if possible, see caveats below) is that the attacker can forge a signature after compromising (and learning the secret shares of) fewer than t participants.
  • It is not clear if there is an attack. It's only plausible in the sense that the attacker needs to solve a new computational problem from which nobody currently knows whether it's hard or not. This is unlike, e.g., the discrete logarithm problem on elliptic curves which has been studied for a long time, so that there's reasonable belief that it's hard.
  • The attack requires the attacker to be adaptive, i.e., the attacker chooses whom to corrupt after seeing the results of key generation including the public shares. This is realistic; and I think users expect that the scheme remains secure if the attacker can do this.
  • The attack requires t and n to be large. For example, a 131-of-196 setup is supposed to be easier to break than simply computing the discrete logarithm of the threshold public key but a 86-of-128 setup won't be affected (see Table 1 in the paper). Concretely, the authors suggest that the attack would be beneficial if effort(n, t) < 128 whereas effort is defined as in this Python code for secp256k1.
    from math import comb, log2
    def effort(n: int, t: int) -> float:
        c = comb(n, t-1)
        return -log2(c / ((2**256) + c))

The big question, of course, is what to do. I think there are two reasonable options:

  1. Forbid affected parameters (n, t) entirely, and explain the rationale.
  2. Only add a warning.

I tend to think that option 1 is better. Of course, that's a restriction in practice, but we can't just move on and pretend that everything will be fine. If someone wants to ignore the restriction, they can still do this, but then they're on their own.

@murchandamus

Copy link
Copy Markdown
Member

Given these new review comments, I expect that we will not publish today. I’ll wait for your input, @siv2r.

@murchandamus murchandamus added the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label Jul 6, 2026
@real-or-random

Copy link
Copy Markdown
Contributor

After consulting with @elizabeth-crites, I have a clearer understanding now, and I should have mentioned also a second paper of her with Jonathan Katz, Chelsea Komlo, Stefano Tessaro, and Chenzhi Zhu (talk; immediately after the other talk in the same video).

In fact, the situation is better than I mentioned. It's not just that we don't know whether an attack exist.

The new paper defines a computational problem LDVR and proves that FROST is adaptively secure when LDVR is hard in addition to the discrete logarithm problem DL (or strictly speaking, its variant AOMDL). Then the paper proves that LDVR is – at least for parameters we're interested in (i.e., small enough n) – so hard that it's better for the attacker to attack DL instead.

Here's improved script that estimates the bit security (function effort) of an attack against LDVR. Here, t_c is the number of actually corrupted parties, i.e., the worst case is t_c = t.)

from math import log2, perm

BITS_GROUP_ORDER = 256

def myperm(n: int, k: int):
    if k >= 1:
        return perm(n, k)
    else:
        return 1

def table1(n: int, t: int, t_c: int | None = None):
    if t_c is None:
        t_c = t  # worst case
    return log2(myperm(n, 2 * t_c - t)/myperm(t_c, 2 * t_c - t))

# Check some numbers from Table 1 in https://eprint.iacr.org/2025/1061
assert table1(128,  96,  round(0.9 *  96)) -  79.24 <= 0.01
assert table1(256,  64,               64 ) - 203.57 <= 0.01
assert table1(1024, 512, round(0.6 * 512)) - 197.18 <= 0.01

def effort(n: int, t: int | None = None, t_c: int | None = None):
    if t is None:
        t = n // 2  # worst case
    return -(table1(n, t, t_c) - BITS_GROUP_ORDER)

DL has an (assumed) bit security of ~128, and to be on the safe side, we want that breaking LDVR is at least as hard, i.e., effort should return at least 128. So to determine safe parameters, the BIP could use rely on the effort function.

There's a cruder but much simpler restriction: As long as n <= 131, we'll always have effort >= 128. So a simple restriction (or recommendation) for the BIP could be simply to require n <= 131 (or maybe n <= 128 to be on the safe side and have a nicer looking number).

I'm pretty sure that 128 parties will be enough for all envisioned currently envisioned use cases of FROST.

Comment thread bip-0445.md

This document specifies the FROST3 variant[^frost3-security]. The FROST3 signing protocol shares substantial similarities with the MuSig2 signing protocol specified in [BIP327][bip327]. Accordingly, this specification adopts several design principles from BIP327, including support for key tweaking, partial signature verification, and identifiable abort mechanisms. We note that significant portions of this document have been directly adapted from BIP327 due to the similarities in the signing protocols. Key generation for FROST signing is out of scope for this document.

[^frost3-security]: The FROST3 signing scheme has been proven existentially unforgeable for both trusted dealer and distributed key generation setups. When using a trusted dealer for key generation, security reduces to the standard One-More Discrete Logarithm (OMDL) assumption. When instantiated with a distributed key generation protocol such as SimplPedPoP, security reduces to the Algebraic One-More Discrete Logarithm (AOMDL) assumption.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
[^frost3-security]: The FROST3 signing scheme has been proven existentially unforgeable for both trusted dealer and distributed key generation setups. When using a trusted dealer for key generation, security reduces to the standard One-More Discrete Logarithm (OMDL) assumption. When instantiated with a distributed key generation protocol such as SimplPedPoP, security reduces to the Algebraic One-More Discrete Logarithm (AOMDL) assumption.
[^frost3-security]: FROST3 has been proven existentially unforgeable under the Algebraic One-More Discrete Logarithm (AOMDL) assumption, for both trusted dealer and distributed key generation using the SimplPedPop protocol[[CGRS23][olaf]].

It's a bit misleading to distinguish OMDL and AOMDL here. The Olaf paper shows unforgeability with SimplPedPop under AOMDL (which is a weaker assumption than OMDL and thus prefereable). Unforgeability with SimplPedPop implies unforgeability with a trusted dealer. As a result, unforgeability in both settings reduces to AODML.

Comment thread bip-0445.md
Algorithm *NonceGen(secshare, pubshare, thresh_pk, m, extra_in)*:

- Inputs:
- The participant secret signing share *secshare*: a 32-byte array, serialized scalar (optional argument)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

micro/consistency nit:
These are called "secret share" everywhere in the BIP except for two places where they're called "secret signing share". Intentional?

@murchandamus

Copy link
Copy Markdown
Member

@siv2r: Please let me know whether you want to go forward with the publication or are still making further updates. The recent review comments could also be addressed in a follow-up authored by another contributor.

@siv2r

siv2r commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

I'm working on fixing the recent review comments. Let's not publish until they're fixed.

Comment thread bip-0445/python/tests.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script always exits with 0, even if tests fail. Strictly speaking, this is not relevant in this BIPs repo because there's no CI. But it's relevant in your repo and it's a footgun for everyone who wants to reuse this code in the future.

(based on a review by Claude Fable 5)

Comment thread bip-0445.md
- Fail if *k<sub>1</sub> = Scalar(0)* or *k<sub>2</sub> = Scalar(0)*[^negligible-zero-scalar]
- Let *R<sub>\*,1</sub> = k<sub>1</sub> &middot; G*, *R<sub>\*,2</sub> = k<sub>2</sub> &middot; G*
- Let *pubnonce = cbytes(R<sub>\*,1</sub>) || cbytes(R<sub>\*,2</sub>)*
- Let *secnonce = scalar_to_bytes(k<sub>1</sub>) || scalar_to_bytes(k<sub>2</sub>)*[^secnonce-ser]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be worth adding a footnote on the difference to BIP327 here. Suggestion:

"BIP 327 appends the serialized individual pk to the secnonce (resulting in a 96-byte secnonce) to avoid a vulnerability that may arise when MuSig2 signers tweak their individual key pair before key aggregation. In FROST, the threshold public key is fixed per FROST key generation and tweaking the public share (which could be seen as the FROST equivalent to an individual public key) is not supported in FROST. Thus, this vulnerability does not apply to FROST, and appending the public share to the secnonce is not necessary.

Comment thread bip-0445.md
It has two optional arguments: *rand*, which can be omitted if randomness is entirely unavailable, and *aggothernonce*, which is omitted by a sole signer (*u = 1*) who has no other signers' nonces to aggregate.
When present, *aggothernonce* should be set to the output of *NonceAgg* run on the *pubnonce* value of **all** other signers (but can be provided by an untrusted party).
Hence, using *DeterministicSign* is only possible for the last signer to generate a nonce, or for a sole signer who is the only participant signing, and it makes the signer stateless, similar to the stateless signer described in the [Nonce Generation](#nonce-generation) section.
In FROST, the deterministic nonce must also bind to the the signer subset *id<sub>1..u</sub>*; otherwise a malicious coordinator can recover the victim's secret share via replayed sessions with varying signer subsets.[^det-signer-set]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: double "the"

Suggested change
In FROST, the deterministic nonce must also bind to the the signer subset *id<sub>1..u</sub>*; otherwise a malicious coordinator can recover the victim's secret share via replayed sessions with varying signer subsets.[^det-signer-set]
In FROST, the deterministic nonce must also bind to the signer subset *id<sub>1..u</sub>*; otherwise a malicious coordinator can recover the victim's secret share via replayed sessions with varying signer subsets.[^det-signer-set]

Comment thread bip-0445.md
| *x[i:j]* | Returns the sub-array of the byte array *x* starting at index *i* (inclusive) and ending at *j* (exclusive). The result has length *j - i* |
| *empty_bytestring* | A constant representing an empty byte array where length is 0 |
| *bytes(n, x)* | Returns the big-endian *n*-byte encoding of the integer *x* |
| *count(x, lst)* | Returns the number of times the element *x* occurs in the list *lst* |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I don't think that one is used at all.

Comment thread bip-0445.md

- Inputs:
- The number *u* of signing participants: an integer with *t ≤ u ≤ n*
- The list of participant public nonces *pubnonce<sub>1..u</sub>*: *u* 66-byte array, each an output of *NonceGen*

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
- The list of participant public nonces *pubnonce<sub>1..u</sub>**u* 66-byte array, each an output of *NonceGen*
- The list of participant public nonces *pubnonce<sub>1..u</sub>**u* 66-byte arrays each an output of *NonceGen*

Comment thread bip-0445.md
- The list of tweak modes *is_xonly_t<sub>1..v</sub>* : *v* booleans
- The message *m*: a byte array[^max-msg-len]

We write "Let *(signers_ctx, aggnonce, v, tweak<sub>1..v</sub>, is_xonly_t<sub>1..v</sub>, m) = session_ctx*" to assign names to the elements of a Session Context.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Claude says that the order in the code is different: (aggnonce, signers_ctx, tweaks, is_xonly, msg). Making pseudocode and consistent helps a reader comparing the two.

Comment thread bip-0445.md
- Input:
- The threshold public key *thresh_pk*: a 33-byte array, compressed serialized point
- Let *Q = cpoint(thresh_pk)*; fail if that fails
- Fail if *is_infinity(Q)*

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I believe this failure is unreachable.

Comment thread bip-0445.md
This signing protocol is compatible with any key generation protocol that produces valid FROST keys.
Valid keys satisfy: (1) each *secret share* is a Shamir share of the *threshold secret key*, and (2) each *public share* equals the scalar multiplication *secshare \* G*.
Before signing, the signers context must pass *ValidateSignersCtx*, which rejects duplicate identifiers and confirms the key material reproduces the threshold public key. The signing algorithms (*Sign*, *PartialSigVerify*, and *PartialSigAgg*) include this check for clarity, so an implementation can instead validate a context once and skip the repeated checks in later calls.
For comprehensive validation of the entire key material, *ValidateSignersCtx* can be run on all possible *u* signing participants.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Do you mean "on the full set of n participants (u = n)" here? Could be clarified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

New BIP PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants